/**
 * Copyright (c) Software Institude of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.modeler.jet.codegen;

import java.io.ByteArrayInputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.codegen.jet.JETEmitter;

import edu.pku.sei.modeler.codegen.Activator;
import edu.pku.sei.modeler.jet.util.ModelerConstants;
import edu.pku.sei.modeler.jet.util.PackageRetriever;
import edu.pku.sei.modeler.model.core.CorePackage;
import edu.pku.sei.modeler.model.core.MetaClass;
import edu.pku.sei.modeler.model.core.MetaModel;
import edu.pku.sei.modeler.model.core.MetaModelElement;

/**
 * @author zl
 * @author zsj add the method to support multi-generalization
 */
public class GenModelCode extends AbstractGenerator {
	private MetaModel model;
	
	public void setModelList(MetaModel model) {
		this.model = model;
	}
	private translated.ModelGen genModel = translated.ModelGen.create("\n");
	private translated.InterfaceGen genInterface = translated.InterfaceGen.create("\n");
	public void generateCode(IProgressMonitor monitor)
			throws InterruptedException {
		try {
/*			String relativeUri = "templates/model/Model.javajet";
			String pluginId = Activator.getPluginId();
			JETEmitter emitter = new JETEmitter(templatesBase + relativeUri, Activator.getDefault().getClass().getClassLoader());
			emitter.addVariable("JET_TUTORIAL", pluginId);
			emitter.addVariable("JET_TUTORIAL", "edu.pku.sei.modeler.runtime");
			emitter.addVariable("EMF_ECORE", "org.eclipse.emf.ecore");
			emitter.addVariable("EMF_COMMON", "org.eclipse.emf.common");
			
			relativeUri = "templates/model/Interface.javajet";
			JETEmitter emitter2 = new JETEmitter(templatesBase + relativeUri, Activator.getDefault().getClass().getClassLoader());
			emitter2.addVariable("JET_TUTORIAL", pluginId);
			emitter2.addVariable("JET_TUTORIAL", "edu.pku.sei.modeler.runtime");
			emitter2.addVariable("EMF_ECORE", "org.eclipse.emf.ecore");
			emitter2.addVariable("EMF_COMMON", "org.eclipse.emf.common");
*/			
			assert proj != null;
			assert model != null;
			
			IFolder folder = proj.getFolder("src");
			Vector<MetaModelElement> modelList = new Vector<MetaModelElement>();
			modelList.addAll(model.getInstancesForType(CorePackage.__METACLASS__));
			modelList.addAll(model.getInstancesForType(CorePackage.__METARELATIONSHIP__));
			
			genFactoryClass(monitor, modelList);
			
			for (Iterator iter = modelList.iterator(); iter.hasNext();) {
				MetaClass cls = (MetaClass)iter.next();
				//String result = emitter.generate(monitor, new Object[]{cls});
				{
					String result = genModel.generate(cls);
					
					//	genInterfaceClass(emitter2,monitor,folder,cls);
					
					String pkgStr = PackageRetriever.retrievePackage(cls);
					pkgStr = pkgStr.replace('.', '/');
					IFolder theFolder = folder.getFolder(pkgStr);
					IFile javaFile = theFolder.getFile(cls.getName()+".java");
					
					ByteArrayInputStream is = new ByteArrayInputStream(result.getBytes());
					javaFile.create(is, true, monitor);
				}
				{
					//String result = emitter.generate(monitor, new Object[] {cls});
					String result = genInterface.generate(cls);
					
					String pkgStr = PackageRetriever.retrievePackage(cls);
					pkgStr = pkgStr.replace('.', '/');
					IFolder theFolder = folder.getFolder(pkgStr);
					IFile javaFile = theFolder.getFile("I" + cls.getName()+".java");
					
					ByteArrayInputStream is = new ByteArrayInputStream(result.getBytes());
					javaFile.create(is, true, monitor);	
				}
			}
			
			genPackageClass(monitor, modelList);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new InterruptedException("generate model code failed");
		}
	}
	
//	/**
//	 * Reorder a metaclass and all its parent classes and subclasses by generalization hierachy in a queue 
//	 * @param cls
//	 * @param classQueue
//	 */
//	private void resortClassesByGeneralization(MetaClass cls,Queue<MetaClass> classQueue) {	
//		if (cls.getGenerals().size() > 0) {
//			MetaTypedList generalizationRelationship = cls.getGenerals();
//			for (int i = 0; i < generalizationRelationship.size(); i++) {
//				resortClassesByGeneralization(((MetaGeneralization)generalizationRelationship.get(i)).getGeneral(),classQueue);
//			}
//			
//		}
//			if (!classQueue.contains(cls)) {
//				classQueue.add(cls);
//			}	
//		
		
		
	//}
	
	/**
	 * Generate a interface for a specified class
	 * @param monitor
	 * @param folder
	 * @param cls the specified class
	 * @throws InterruptedException
	 */
	/*private void genInterfaceClass(JETEmitter emitter, IProgressMonitor monitor, IFolder folder, MetaClass cls) throws InterruptedException {
		try {
			String result = emitter.generate(monitor, new Object[] {cls});
			
			String pkgStr = PackageRetriever.retrievePackage(cls);
			pkgStr = pkgStr.replace('.', '/');
			IFolder theFolder = folder.getFolder(pkgStr);
			IFile javaFile = theFolder.getFile("I" + cls.getName()+".java");
			
			ByteArrayInputStream is = new ByteArrayInputStream(result.getBytes());
			javaFile.create(is, true, monitor);	
			
		}catch (Exception e) {
			e.printStackTrace();
			throw new InterruptedException("generate interface code failed");
			
		}
	}*/
	private translated.PackageGen genPackage = translated.PackageGen.create("\n");
	public void genPackageClass(IProgressMonitor monitor, List modelList)
		throws InterruptedException {
		/*String relativeUri = "templates/model/Package.javajet";
		JETEmitter emitter = new JETEmitter(templatesBase + relativeUri, Activator.getDefault().getClass().getClassLoader());
		String pluginId = Activator.getPluginId();*/
		try {
			/*emitter.addVariable("JET_TUTORIAL", pluginId);
			emitter.addVariable("JET_TUTORIAL", "edu.pku.sei.modeler.runtime");
			emitter.addVariable("EMF_ECORE", "org.eclipse.emf.ecore");
			emitter.addVariable("EMF_COMMON", "org.eclipse.emf.common");*/
			
			//String result = emitter.generate(monitor, new Object[] { modelList });
			String result = genPackage.generate(modelList);
			String modelBase = ModelerConstants.pkgBase + "." + ModelerConstants.modelBase;
			IFolder folder = proj.getFolder("src/"+modelBase.replace('.', '/'));
			IFile javaFile = folder.getFile("ModelPackage"+".java");
			ByteArrayInputStream is = new ByteArrayInputStream(result.getBytes());
			javaFile.create(is, true, monitor);
		} catch (Exception e) {
			e.printStackTrace();
			throw new InterruptedException("generate package failed");
		}
	}
	private translated.FactoryGen genFactory = translated.FactoryGen.create("\n");
	
	public void genFactoryClass(IProgressMonitor monitor, List modelList)
		throws InterruptedException {
/*		String relativeUri = "templates/model/Factory.javajet";
		JETEmitter emitter = new JETEmitter(templatesBase + relativeUri, Activator.getDefault().getClass().getClassLoader());
		String pluginId = Activator.getPluginId();
*/		try {
/*			emitter.addVariable("JET_TUTORIAL", pluginId);
			emitter.addVariable("JET_TUTORIAL", "edu.pku.sei.modeler.runtime");
			emitter.addVariable("EMF_ECORE", "org.eclipse.emf.ecore");
			emitter.addVariable("EMF_COMMON", "org.eclipse.emf.common");
*/			//FIXME: EXCEPTION
			
			String result = genFactory.generate(modelList);
			
			//String result = emitter.generate(monitor, new Object[] { modelList });
			String modelBase = ModelerConstants.pkgBase + "." + ModelerConstants.modelBase;
			IFolder folder = proj.getFolder("src/"+modelBase.replace('.', '/'));
			IFile javaFile = folder.getFile("ModelFactory"+".java");
			ByteArrayInputStream is = new ByteArrayInputStream(result.getBytes());
			javaFile.create(is, true, monitor);
		} catch (Exception e) {
			e.printStackTrace();
			throw new InterruptedException("generate package failed");
		}
	}
}
